/**
 * ReportGear(2011)
 */
package com.reportgear.report.model.cell.style;

import java.awt.Color;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.reportgear.core.api.XmlSerializerWithReadReturn;
import com.reportgear.report.model.cell.style.background.Background;

/**
 * 单元格样式
 * 
 * @version 1.0 2011-3-9
 * @author <a herf="lexloo@gmail.com">lexloo</a>
 * @since Report 1.0
 */
public class Style implements XmlSerializerWithReadReturn<Style> {
	// 日志记录
	private static Logger logger = LoggerFactory.getLogger(Style.class.getName());
	// 单元格文本样式
	private TextStyle textStyle = TextStyle.WORDWRAP;
	// 水平对齐方式
	private HorizentalAlignment horizentalAlignment = HorizentalAlignment.CENTER;
	// 垂直对齐方式
	private VerticalAlignment verticalAlignment = VerticalAlignment.MIDDLE;
	// 边框样式
	private BorderStyle borderStyle = BorderStyle.DEFAULT_STYLE;
	// 字体样式
	private FontStyle fontStyle = FontStyle.DEFAULT_STYLE;
	// 背景
	private Background background = null;
	// 格式化样式key
	private String formatterKey = "";
	// 样式缓存
	private static Map<Style, Style> cachedStyle = new WeakHashMap<Style, Style>();
	// 默认样式
	public static Style DEFAULT_STYLE = new Style();

	public static Style getInstance() {
		Style tmpStyle = new Style();
		Style style = cachedStyle.get(tmpStyle);

		if (null != style) {
			return style;
		}

		cachedStyle.put(tmpStyle, tmpStyle);

		if (logger.isDebugEnabled()) {
			logger.debug("添加新单元格样式, 样式总数:{}", cachedStyle.size());
		}

		return tmpStyle;
	}

	public static Style getInstance(Background background, String formatter, FontStyle fontStyle,
			BorderStyle borderStyle, HorizentalAlignment horizentalAlignment, VerticalAlignment verticalAlignment,
			TextStyle textStyle) {

		Style tmpStyle = new Style(background, formatter, fontStyle, borderStyle, horizentalAlignment,
				verticalAlignment, textStyle);
		Style style = cachedStyle.get(tmpStyle);

		if (style != null) {
			return style;
		}

		cachedStyle.put(tmpStyle, tmpStyle);

		if (logger.isDebugEnabled()) {
			logger.debug("添加新单元格样式, 样式总数:{}", cachedStyle.size());
		}

		return tmpStyle;
	}

	/**
	 * 获取所有样式
	 * 
	 * @return 所有样式
	 */
	public static Set<Style> getStyleSet() {
		return Collections.unmodifiableSet(cachedStyle.keySet());
	}

	public Style deriveBorder(BorderStyle borderStyle) {
		return getInstance(this.background, this.formatterKey, this.fontStyle, borderStyle, this.horizentalAlignment,
				this.verticalAlignment, this.textStyle);
	}

	public Style deriveBorder(int topStyle, Color topColor, int leftStyle, Color leftColor, int bottomStyle,
			Color bottomColor, int rightStyle, Color rightColor) {

		BorderStyle tmpBorder = new BorderStyle(topStyle, topColor, leftStyle, leftColor, bottomStyle, bottomColor,
				rightStyle, rightColor);

		return getInstance(this.background, this.formatterKey, this.fontStyle, tmpBorder, this.horizentalAlignment,
				this.verticalAlignment, this.textStyle);
	}

	public Style deriveFormatterKey(String formatter) {
		return getInstance(this.background, formatter, this.fontStyle, this.borderStyle, this.horizentalAlignment,
				this.verticalAlignment, this.textStyle);
	}

	public Style deriveReportFont(FontStyle fontStyle) {
		return getInstance(this.background, this.formatterKey, fontStyle, this.borderStyle, this.horizentalAlignment,
				this.verticalAlignment, this.textStyle);
	}

	public Style deriveReportAlign(HorizentalAlignment horizentalAlignment, VerticalAlignment verticalAlignment,
			TextStyle textStyle) {
		return getInstance(this.background, this.formatterKey, this.fontStyle, this.borderStyle, horizentalAlignment,
				verticalAlignment, textStyle);
	}

	public Style derivetHorizentalAlignment(HorizentalAlignment horizentalAlignment) {
		return getInstance(this.background, this.formatterKey, this.fontStyle, this.borderStyle, horizentalAlignment,
				this.verticalAlignment, this.textStyle);
	}

	public Style derivetVerticalAlignment(VerticalAlignment verticalAlignment) {
		return getInstance(this.background, this.formatterKey, this.fontStyle, this.borderStyle,
				this.horizentalAlignment, verticalAlignment, this.textStyle);
	}

	public Style derivetTextStyle(TextStyle textStyle) {
		return getInstance(this.background, this.formatterKey, this.fontStyle, this.borderStyle,
				this.horizentalAlignment, this.verticalAlignment, textStyle);
	}

	/**
	 * 构造器
	 */
	private Style() {
	}

	/**
	 * 构造器
	 * 
	 * @param background
	 * @param formatter
	 * @param fontStyle
	 * @param borderStyle
	 * @param horizentalAlignment
	 * @param verticalAlignment
	 * @param textStyle
	 */
	private Style(Background background, String formatter, FontStyle fontStyle, BorderStyle borderStyle,
			HorizentalAlignment horizentalAlignment, VerticalAlignment verticalAlignment, TextStyle textStyle) {
		this.background = background;
		this.formatterKey = formatter;
		this.fontStyle = fontStyle;
		this.borderStyle = borderStyle;
		this.horizentalAlignment = horizentalAlignment;
		this.verticalAlignment = verticalAlignment;
		this.textStyle = textStyle;
	}

	public TextStyle getTextStyle() {
		return textStyle;
	}

	public HorizentalAlignment getHorizentalAlignment() {
		return this.horizentalAlignment;
	}

	public VerticalAlignment getVerticalAlignment() {
		return this.verticalAlignment;
	}

	public BorderStyle getBorderStyle() {
		if (this.borderStyle == null) {
			return BorderStyle.DEFAULT_STYLE;
		}

		return this.borderStyle;
	}

	public FontStyle getFontStyle() {
		if (this.fontStyle == null) {
			return FontStyle.DEFAULT_STYLE;
		}

		return this.fontStyle;
	}

	public Background getBackground() {
		return this.background;
	}

	public String getFormatterKey() {
		return this.formatterKey;
	}

	public int getPaddingRight() {
		// TODO Auto-generated method stub
		return 0;
	}

	public double getPaddingLeft() {
		// TODO Auto-generated method stub
		return 0;
	}

	public double getSpacingBefore() {
		// TODO Auto-generated method stub
		return 0;
	}

	public double getSpacingAfter() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public Style read(Element parent) {
		if (parent == null) {
			return this;
		}

		Style style = this;

		style = style
				.derivetHorizentalAlignment(style.getHorizentalAlignment().getByCode(parent.elementTextTrim("ha")));
		style = style.derivetVerticalAlignment(style.getVerticalAlignment().getByCode(parent.elementTextTrim("va")));
		style = style.derivetTextStyle(TextStyle.valueOf(parent.elementTextTrim("ts")));
		style = style.deriveFormatterKey(parent.elementTextTrim("fmt"));

		FontStyle fontStyle = style.fontStyle.read(parent.element("font"));
		style = style.deriveReportFont(fontStyle);

		BorderStyle borderStyle = style.borderStyle.read(parent.element("br"));
		style = style.deriveBorder(borderStyle);

		return style;
	}

	@Override
	public void write(Element parent) {
		Element el = parent.addElement("ha");
		el.addText(this.horizentalAlignment.getCode());

		el = parent.addElement("va");
		el.addText(this.verticalAlignment.getCode());

		el = parent.addElement("ts");
		el.addText(this.textStyle.toString());

		el = parent.addElement("fmt");
		el.addText(this.formatterKey);

		el = parent.addElement("font");
		this.fontStyle.write(el);

		el = parent.addElement("br");
		this.borderStyle.write(el);

		// TODO 写入背景
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((background == null) ? 0 : background.hashCode());
		result = prime * result + ((borderStyle == null) ? 0 : borderStyle.hashCode());
		result = prime * result + ((fontStyle == null) ? 0 : fontStyle.hashCode());
		result = prime * result + ((formatterKey == null) ? 0 : formatterKey.hashCode());
		result = prime * result + ((horizentalAlignment == null) ? 0 : horizentalAlignment.hashCode());
		result = prime * result + ((textStyle == null) ? 0 : textStyle.hashCode());
		result = prime * result + ((verticalAlignment == null) ? 0 : verticalAlignment.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Style other = (Style) obj;
		if (background == null) {
			if (other.background != null)
				return false;
		} else if (!background.equals(other.background))
			return false;
		if (borderStyle == null) {
			if (other.borderStyle != null)
				return false;
		} else if (!borderStyle.equals(other.borderStyle))
			return false;
		if (fontStyle == null) {
			if (other.fontStyle != null)
				return false;
		} else if (!fontStyle.equals(other.fontStyle))
			return false;
		if (formatterKey == null) {
			if (other.formatterKey != null)
				return false;
		} else if (!formatterKey.equals(other.formatterKey))
			return false;
		if (horizentalAlignment == null) {
			if (other.horizentalAlignment != null)
				return false;
		} else if (!horizentalAlignment.equals(other.horizentalAlignment))
			return false;
		if (textStyle == null) {
			if (other.textStyle != null)
				return false;
		} else if (!textStyle.equals(other.textStyle))
			return false;
		if (verticalAlignment == null) {
			if (other.verticalAlignment != null)
				return false;
		} else if (!verticalAlignment.equals(other.verticalAlignment))
			return false;
		return true;
	}
}
